<!DOCTYPE html>
<!--
Copyright 2017 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->

<link rel="import" href="/tracing/core/test_utils.html">
<link rel="import" href="/tracing/extras/importer/fuchsia_importer.html">
<link rel="import" href="/tracing/extras/importer/trace_event_importer.html">

<script>
'use strict';

tr.b.unittest.testSuite(function() {
  function newModel(events) {
    return tr.c.TestUtils.newModelWithEvents([events], {
      shiftWorldToZero: false
    });
  }

  // Test that fuchsia process and thread info events properly annotate
  // thread and process names.
  test('processAndThreadInfo', function() {
    const events = `{
      "displayTimeUnit": "ns",
      "traceEvents": [
        {
          "cat": "cat0",
          "name": "name0",
          "ts": 1.0,
          "pid": 1,
          "tid": 2,
          "ph": "B"
        },
        {
          "cat": "cat0",
          "name": "name0",
          "ts": 2.0,
          "pid": 1,
          "tid": 2,
          "ph": "E"
        }
      ],
      "systemTraceEvents": {
        "type": "fuchsia",
        "events": [
          {
            "ph": "p",
            "pid": 1,
            "name": "proc1"
          },
          {
            "ph": "t",
            "pid": 1,
            "tid": 2,
            "name": "thread2"
          }
        ]
      }
    }`;
    const m = tr.c.TestUtils.newModelWithEvents([events], {
      shiftWorldToZero: false
    });
    const process = m.getProcess(1);
    assert.isDefined(process);
    assert.strictEqual(process.name, 'proc1');

    const thread = process.getThread(2);
    assert.isDefined(thread);
    assert.strictEqual(thread.name, 'thread2');
  });

  // Test that context switch events create CPU slices.
  test('cpuSlices', function() {
    const events = `{
      "displayTimeUnit": "ns",
      "traceEvents": [
      ],
      "systemTraceEvents": {
        "type": "fuchsia",
        "events": [
          {
            "ph": "p",
            "pid": 1,
            "name": "proc1"
          },
          {
            "ph": "t",
            "pid": 1,
            "tid": 2,
            "name": "thread2"
          },
          {
            "ph": "t",
            "pid": 1,
            "tid": 3,
            "name": "thread3"
          },
          {
            "ph": "k",
            "ts": 1.0,
            "cpu": 1,
            "out": {
              "pid": 1,
              "tid": 2,
              "state": 1
            },
            "in": {
              "pid": 1,
              "tid": 3
            }
          },
          {
            "ph": "k",
            "ts": 2.0,
            "cpu": 1,
            "out": {
              "pid": 1,
              "tid": 3,
              "state": 3
            },
            "in": {
              "pid": 1,
              "tid": 2
            }
          },
          {
            "ph": "k",
            "ts": 3.0,
            "cpu": 1,
            "out": {
              "pid": 1,
              "tid": 2,
              "state": 1
            },
            "in": {
              "pid": 1,
              "tid": 3
            }
          }
        ]
      }
    }`;
    const m = tr.c.TestUtils.newModelWithEvents([events], {
      shiftWorldToZero: false
    });
    const cpu = m.kernel.cpus[1];
    assert.isDefined(cpu);
    assert.strictEqual(cpu.slices.length, 2);

    assert.strictEqual(cpu.slices[0].title, 'proc1:thread3');
    assert.closeTo(cpu.slices[0].duration, 0.001, 1e-5);

    assert.strictEqual(cpu.slices[1].title, 'proc1:thread2');
    assert.closeTo(cpu.slices[1].duration, 0.001, 1e-5);

    const SCHEDULING_STATE = tr.model.SCHEDULING_STATE;

    const thread2Slices =
      m.getOrCreateProcess(1).getOrCreateThread(2).timeSlices;
    assert.strictEqual(thread2Slices[0].schedulingState,
        SCHEDULING_STATE.RUNNABLE);
    assert.closeTo(thread2Slices[0].start, 0.001, 1e-5);
    assert.closeTo(thread2Slices[0].duration, 0.001, 1e-5);
    assert.strictEqual(thread2Slices[1].schedulingState,
        SCHEDULING_STATE.RUNNING);
    assert.closeTo(thread2Slices[1].start, 0.002, 1e-5);
    assert.closeTo(thread2Slices[1].duration, 0.001, 1e-5);

    const thread3Slices =
      m.getOrCreateProcess(1).getOrCreateThread(3).timeSlices;
    assert.strictEqual(thread3Slices[0].schedulingState,
        SCHEDULING_STATE.RUNNING);
    assert.closeTo(thread3Slices[0].start, 0.001, 1e-5);
    assert.closeTo(thread3Slices[0].duration, 0.001, 1e-5);
    assert.strictEqual(thread3Slices[1].schedulingState,
        SCHEDULING_STATE.SLEEPING);
    assert.closeTo(thread3Slices[1].start, 0.002, 1e-5);
    assert.closeTo(thread3Slices[1].duration, 0.001, 1e-5);
  });
});
</script>
